﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Threading.Tasks;
using System.Threading;
using Shoozla.DataModel.Helper;
using System.Diagnostics;

namespace Shoozla.DataModel
{
    /// <summary>
    /// Scan list and read all the Mp3 file found 
    /// </summary>
    public class FileReader : IProgressOperation
    {
        //interface implementation
        public int Minimum { get; set; }
        public int Maximum { get; set; }
        public int Current { get; set; }
        public String Description { get; set; }

        public event EventHandler<ProgressOperationEventArgs> ProgressChanged;
        public event EventHandler<ProgressOperationEventArgs> Completed;
        public event EventHandler<ProgressOperationEventArgs> Started;


        public List<Mp3File> Songs { get; private set; }
        private List<FileInfo> _files;

        private CancellationTokenSource _cancelToken;
        private IMP3Processor _mp3Processor;

        public FileReader(CancellationTokenSource cancelToken, IMP3Processor mp3Processor)
        {
            _cancelToken = cancelToken;
            _mp3Processor = mp3Processor;
            Songs = new List<Mp3File>();
            Current = 0;
            Maximum = 0;
            Minimum = 0;
        }

        public void CancelAsync() { _cancelToken.Cancel(); }

        /// <summary>
        /// the folder will be scanned for Mp3
        /// </summary>
        /// <param name="folder">folder to scan</param>
        /// <returns>number of Mp3 file</returns>
        public int ReadCollection(List<FileInfo> files)
        {
            Maximum = files.Count;
            _files = files;
            Description = "Reading "+Maximum+" files";
            Current = 0;
            return Maximum;
        }

        public void Start()
        {
            Task.Factory.StartNew((Action)(()=>{

            if (_files != null)
            {               
                if (Started != null)
                    foreach (Delegate d in Started.GetInvocationList())
                    {
                        d.DynamicInvoke(new object[] { null, new ProgressOperationEventArgs(0, Maximum, Description) });
                    }
                try
                {

                    ParallelOptions paralleSettings = new ParallelOptions();
                    paralleSettings.CancellationToken = _cancelToken.Token;
                    paralleSettings.MaxDegreeOfParallelism = ThreadHelper.CalculateTreads(Songs.Count(), ThreadingFactorEnum.Maximum);
                    //saving Mp3 in a parallel way
                    Parallel.ForEach<FileInfo>(_files, paralleSettings, (f) =>
                    {                        
                        try
                        {
                            Mp3File m = _mp3Processor.ReadID3Tag(f,false);
                            if (m != null)
                            {
                                //to save memory, unload the image
                                Songs.Add(m);
                            }

                            Current++;
                            if (ProgressChanged != null)
                                foreach (Delegate d in ProgressChanged.GetInvocationList())
                                {
                                    d.DynamicInvoke(new object[] { this, new ProgressOperationEventArgs(Current, Maximum, Description) });

                                }
                        }
                        catch (OperationCanceledException ce)
                        {
                            //user interrupted the operation
                            Trace.WriteLine("[INFO] FileReader: Operation stopped");
                        }
                        catch (Exception e)
                        {
                            Trace.WriteLine("[ERROR] FileReader: Song not read: " + e.Message);
                        }

                    });
                }
                catch (AggregateException ae)
                {
                    //do nothing
                }
                finally
                {

                    if (Completed != null)
                        foreach (Delegate d in Completed.GetInvocationList())
                        {
                            d.DynamicInvoke(new object[] { this, new ProgressOperationEventArgs(Current, Maximum, Description) });
                        }
                }
            }
            }));
            
        }
    }
}
